﻿using System.Collections.Generic;
using System.Threading;
using DBServer.Selenium.Extenium.Exception;
using DBServer.Selenium.Extenium.Path;
using Selenium;
using System.Text;
using System.Linq;

namespace DBServer.Selenium.Extenium.Fixtures
{
    public class ComboBoxFixture : ExtComponentFixture
    {
        private readonly IPath _path;

        public ComboBoxFixture(ISelenium driver, IPath path)
            : base(driver, path)
        {
            _path = path;
        }

        /*private bool WaitUntilLoaded()
        {
            var command = Path.Eval() + ".store.data.length";
            for ( int i=0; i<10; i++ )
            {
                var length = int.Parse(SafeExec(command));
                if (length > 0)
                {
                    return true;
                }
                Thread.Sleep(100);
            }
            return false;
        }*/

        protected void RequireStoreIsLoaded()
        { 
            SafeExec(Path.Eval() + ".store.load()");
            
            //Wait until we have a correct value in the store
            int outter;
            Wait(() => (int.TryParse(SafeExec(Path.Eval() + ".store.data.length"), out outter)));
            //Wait until exists some value in the store
            Wait(() => (int.Parse(SafeExec(Path.Eval() + ".store.data.length")))!=0);
        }

        public ComboBoxFixture SetValue(string value)
        {
            var command = "var cmb = " + Path.Eval() + "; " +
                          "var record = cmb.findRecord(cmb.displayField, '" + value + "'); " +
                          "cmb.onSelect(record);";

            RequireStoreIsLoaded();
            SafeExec(command);
            return this;
        }

        /* Substituido por apenas setar o valor na interface
         * public ComboBoxFixture SetValue(string value)
        {
            var command = new StringBuilder();
            command.Append(" var value = '").Append(value).Append("';");
            command.Append(" var combo = ").Append(Path.Eval()).Append(";");
            command.Append(" var valueField = combo.valueField;");
            command.Append(" var displayField = combo.displayField;");
            command.Append(" var elements = combo.store.data.items;");
            command.Append(" var valueWasSet = false;");
            command.Append(" for (var i = 0; i < elements.length; i++) {");
            command.Append("     var displayValue = eval('elements[i].data.' + displayField);");
            command.Append("     if (displayValue == value) {");
            command.Append("         var value = eval('elements[i].data.' + valueField);");
            command.Append("         combo.setValue(value);");
            command.Append("         valueWasSet = true;");
            command.Append("         break;");
            command.Append("     }");
            command.Append(" }");
            command.Append(" valueWasSet;");

            RequireStoreIsLoaded();
            var eval = SafeExec(command.ToString());
            if (!bool.Parse(eval))
            {
                throw new ExteniumException("Could not set combo value: " + value);
            }
            return this;
        }*/

        public ComboBoxFixture RequireOptionPresent(string option)
        {
            var options = GetActualOptionSet();
            var exist = options.Contains(option);
            if ( !exist )
            {
                throw new ExteniumException(option + " was not present");
            }
            return this;
        }

        public ComboBoxFixture RequireOptionAbsent(string option)
        {
            var options = GetActualOptionSet();
            var exist = options.Contains(option);
            if (exist)
            {
                throw new ExteniumException(option + " was not absent");
            }
            return this;
        }
        
        public ComboBoxFixture RequireOptionSet(params string[] options)
        {
            var actualOptionSet = GetActualOptionSet();
            var expectedOptionSet = new HashSet<string>(options);

            if (!actualOptionSet.SetEquals(expectedOptionSet))
            {
                throw new ExteniumException("Combo box doesn't contains expected option set");
            }
            return this;
        }

        private HashSet<string> GetActualOptionSet()
        {
            var command = new StringBuilder();
            command.Append(" var optionSet = '';");
            command.Append(" var combo = ").Append(Path.Eval()).Append(";");
            command.Append(" var displayField = combo.displayField;");
            command.Append(" var elements = combo.store.data.items;");
            command.Append(" for (var i = 0; i < elements.length; i++) {");
            command.Append("     var displayValue = eval('elements[i].data.' + displayField);");
            command.Append("     if (optionSet.length > 0) {");
            command.Append("        optionSet = optionSet.concat('|');");
            command.Append("     }");
            command.Append("     optionSet = optionSet.concat(displayValue);");
            command.Append(" }");
            command.Append(" optionSet;");

            RequireStoreIsLoaded();
            var eval = SafeExec(command.ToString());
            var actualOptions = eval.Split('|');

            return new HashSet<string>(actualOptions);
        }

        public ComboBoxFixture RequireValue(string text)
        {
            RequireStoreIsLoaded();
            var value = SafeExec(_path.Eval() + ".getRawValue();");

            if (value != text)
            {
                throw new ExteniumException("Unexpected combo value: " + value + " (expected: " + text + ")");
            }
            return this;
        }

        public ComboBoxFixture Click()
        {
            RequireStoreIsLoaded();
            SafeExec(_path.Eval() + ".el.dom.click()");
            return this;
        }
    }
}
